package com.example.edu.Utils;

import com.example.edu.Dto.DocumentLikeCollectViewDto;
import com.example.edu.Entity.Document;
import com.example.edu.Entity.EsDocument;
import com.example.edu.Entity.Picture;
import com.example.edu.Entity.Tag;
import com.example.edu.Mapper.DocumentMapper;
import com.example.edu.Mapper.PictureMapper;
import com.example.edu.Mapper.TagMapper;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.io.File;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;

import static com.example.edu.Utils.MyConstants.*;

@Component
public class ScheduledUtil {
    @Resource
    TagMapper tagMapper;
    @Resource
    PictureMapper pictureMapper;
    @Resource
    DocumentMapper documentMapper;
    @Resource
    StringRedisTemplate stringRedisTemplate;
    @Resource
    CacheDataBaseUtil cacheDataBaseUtil;
    @Resource
    EmbeddingUtil embeddingUtil;
    @Resource
    EsUtil esUtil;
    private static final Logger logger = LoggerFactory.getLogger(ScheduledUtil.class);

    @Scheduled(cron = "0 35 4 */7 * ?")
    @Transactional(rollbackFor = Exception.class)
    public void cleanUnusedTag(){
        List<Tag> wild_tags = tagMapper.getWildTag();
        List<String> tag_names = new ArrayList<>();
        List<Integer> tag_ids = new ArrayList<>();
        for(Tag wild_tag : wild_tags) {
            tag_names.add(wild_tag.getTag_name());
            tag_ids.add(wild_tag.getTag_id());
        }
        try{
            if(!tag_ids.isEmpty())
                cacheDataBaseUtil.deleteManyById2(TAG_KEY,tag_ids,tag_names,tag_ids2 -> tagMapper.deleteByIds(tag_ids2));
        }catch (Exception e){
            logger.error(e.getMessage());
            throw new RuntimeException(e);
        }
    }

    @Scheduled(cron = "0 30 4 */7 * ?")
    @Transactional(rollbackFor = Exception.class)
    public void cleanUnusedPicture(){
        List<Picture> wild_pictures = pictureMapper.getWildPicture();
        List<String> md5s = new ArrayList<>();
        List<String> paths = new ArrayList<>();
        for(Picture wild_picture : wild_pictures) {
            md5s.add(wild_picture.getKey());
            paths.add(PICTURE_ADDRESS + "/" + wild_picture.getPicture_id() + "." + wild_picture.getType());
        }
        try {
            if(!md5s.isEmpty()) {
                cacheDataBaseUtil.deleteManyById(PICTURE_KEY, md5s, md5s2 -> pictureMapper.deleteByKeys(md5s2));
                for (String path : paths) {
                    File file = new File(path);
                    if (file.exists())
                        file.delete();
                }
            }
        }catch (Exception e){
            logger.error(e.getMessage());
            throw new RuntimeException(e);
        }
    }

    @Scheduled(cron = "0 0 * * * ?")
    public void saveLikeCollectView(){
        List<Integer> document_ids = documentMapper.getIds();
        if(document_ids.isEmpty())
            return;
        List<DocumentLikeCollectViewDto> likeCollectViewData = new ArrayList<>();
        String key,value;
        int like,collects,views;
        for(int document_id : document_ids){
            key = LIKE_KEY + document_id;
            value = stringRedisTemplate.opsForValue().get(key);
            like = value != null ? Integer.parseInt(value) : 0;
            stringRedisTemplate.opsForValue().set(key,"0");
            key = COLLECT_KEY + document_id;
            value = stringRedisTemplate.opsForValue().get(key);
            collects = value != null ? Integer.parseInt(value) : 0;
            stringRedisTemplate.opsForValue().set(key,"0");
            key = VIEW_KEY + document_id;
            value = stringRedisTemplate.opsForValue().get(key);
            views = value != null ? Integer.parseInt(value) : 0;
            stringRedisTemplate.opsForValue().set(key,"0");
            likeCollectViewData.add(new DocumentLikeCollectViewDto(document_id,views,like,collects));
        }
        documentMapper.updateLikeCollectView(likeCollectViewData);
    }

    @Scheduled(fixedRate = 120000)
    public void sendToES(){
        Set<String> document_keys = stringRedisTemplate.keys(LAST_SAVE_KEY+"*");
        if (document_keys == null || document_keys.isEmpty())
            return;
        List<Integer> document_ids = new ArrayList<>();
        List<String> documentIds = new ArrayList<>();
        for(String key : document_keys){
            String v = stringRedisTemplate.opsForValue().get(key);
            if(v == null)
                continue;
            long last_time = Long.parseLong(v);
            if(System.currentTimeMillis() - last_time < DELAY_TIME)
                continue;
            int document_id = Integer.parseInt(key.substring(9));
            document_ids.add(document_id);
            documentIds.add(String.valueOf(document_id));
        }
        if(document_ids.isEmpty())
            return;
        List<Document> documents = documentMapper.getESDocumentMessage(document_ids);
        List<EsDocument> esDocuments = new ArrayList<>();
        for(int index = 0;index < document_ids.size();index++){
            int document_id = document_ids.get(index);
            Document document = documents.get(index);
            String path = DOCUMENT_ADDRESS + "/" + document_id + ".json";
            try {
                String content = new String(Files.readAllBytes(Paths.get(path)), StandardCharsets.UTF_8);
                if(content.isEmpty())
                    continue;
                ObjectMapper objectMapper = new ObjectMapper();
                JsonNode root = objectMapper.readTree(content).get("root");
                JsonNode children = root.get("children");
                if (children != null && children.isArray()) {
                    List<String> slices = RegexUtils.extractTextSlices(children);
//                    System.out.println("size: "+slices.size());
//                    for (String slice : slices) {
//                        System.out.println("---切片---\n" + slice + "\n");
//                    }
                    if(slices.isEmpty())
                        continue;
                    List<List<Double>> embeddings = embeddingUtil.getEmbeddings(slices);
                    for(int i = 0;i < slices.size();i++){
                        EsDocument esDocument = new EsDocument(document_id,i,document.getDocument_name(),document.getDocument_course(),document.getDocument_chapter()
                                ,document.getIs_outline(),document.getIs_plan(),slices.get(i),embeddings.get(i));
                        esDocuments.add(esDocument);
                    }
                }
            } catch (Exception e){
                logger.error(e.getMessage());
            }
        }
        try {
            logger.info("start sendToES");
            esUtil.deleteDocuments(documentIds);
            if(!esDocuments.isEmpty())
                esUtil.insertDocuments(esDocuments);
            logger.info("end sendToES");
        } catch (Exception e){
            logger.error(e.getMessage());
        }
    }
}
